package apkg;


import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.RMISecurityManager;
import java.util.UUID;
import java.util.Vector;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.jws.WebService;
import javax.servlet.http.HttpSession;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.soap.MTOM;

import com.sun.jersey.api.core.PackagesResourceConfig;

import distrcomp.Address;


import be.ac.ua.codebase.*;

import net.jini.core.discovery.LookupLocator;
import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceID;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.transaction.Transaction;
import net.jini.core.transaction.Transaction.Created;
import net.jini.core.transaction.TransactionFactory;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.lookup.entry.Name;
import net.jini.space.JavaSpace;


@MTOM
@WebService
public class TestWebService implements TestWebServiceInterface {
	
	@Resource
    private WebServiceContext wsContext;

	public TestWebService() {
		System.out.println("webservice constructor");
	}
	
	private HttpSession getSession() {
		MessageContext mc = wsContext.getMessageContext();
        HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession();            
        return session;
	}
	
	private String getReggie() {
		try{
			FileInputStream fstream = new FileInputStream("resources/reggie.txt");
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null)   {
				break;
			}
			in.close();
			return strLine;
		}catch (Exception e){
			System.err.println("Error: " + e.getMessage());
		}
		return "jini://localhost";
	}
	
	private String getCodebase() {
		try{
			FileInputStream fstream = new FileInputStream("resources/codebase.txt");
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null)   {
				break;
			}
			in.close();
			return strLine;
		}catch (Exception e){
			System.err.println("Error: " + e.getMessage());
		}
		return "http://localhost:8080/";
	}
	
	@Override
	public String sayHello(String name) {
		return "Dag " + name;
	}
	
	@Override
	public void setup(String firstName, String familyName, String postalCode, String number, String city, String country, String street) {
		System.setProperty("java.security.policy", "resources/policies.policy");
		System.setProperty("java.rmi.server.codebase", getCodebase());
		System.setSecurityManager(new RMISecurityManager());
		
		HttpSession session = getSession();
		session.setAttribute("reggie", getReggie());
        session.setAttribute("firstname", firstName);
        session.setAttribute("familyname", familyName);
        session.setAttribute("postalcode", postalCode); 
        session.setAttribute("number", number);
        session.setAttribute("city", city);
        session.setAttribute("country", country);
        session.setAttribute("street", street);
	}
	
	private String getReggieUrl() {
		HttpSession session = getSession();
		return (String)session.getAttribute("reggie");
	}
	
	private BankInterface getBank() {
		try {
			LookupLocator lookup = new LookupLocator(getReggieUrl()); 
			ServiceRegistrar registrar = lookup.getRegistrar();
			
			HttpSession session = getSession();
			if (session.getAttribute("bankid") == null) {
				System.out.println("search new bank");
				Class[] classes = new Class[] {BankInterface.class};
				BankInterface tmp = (BankInterface) registrar.lookup(new ServiceTemplate(null, classes, null));
				session.setAttribute("bankid", tmp.getName());
				System.out.println("found1");
				return tmp;
			} else {
				System.out.println("try to find old bank");
				Entry[] attributes = new Entry[] {new Name((String)session.getAttribute("bankid"))}; 
				Class[] classes = new Class[] {BankInterface.class};
				UUID id = UUID.fromString((String)session.getAttribute("bankid"));
				ServiceID serviceId = new ServiceID(id.getMostSignificantBits(), id.getLeastSignificantBits());
				BankInterface tmp = (BankInterface) registrar.lookup(new ServiceTemplate(serviceId, null, null));
				System.out.println("found2");
				return tmp;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private StoreConnectorInterface getStoreConnector() {
		try {
			LookupLocator lookup = new LookupLocator(getReggieUrl()); 
			ServiceRegistrar registrar = lookup.getRegistrar();
			Class[] classes = new Class[] {StoreConnectorInterface.class};
			StoreConnectorInterface tmp = (StoreConnectorInterface) registrar.lookup(new ServiceTemplate(null, classes, null));
			return tmp;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private JavaSpace getSpace() {
		try {
			LookupLocator lookup = new LookupLocator(getReggieUrl()); 
			ServiceRegistrar registrar = lookup.getRegistrar();
			Class[] classes = new Class[] {JavaSpace.class};
			JavaSpace tmp = (JavaSpace) registrar.lookup(new ServiceTemplate(null, classes, null));
			return tmp;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private TransactionManager getTransactionManager() {
		try {
			LookupLocator lookup = new LookupLocator(getReggieUrl()); 
			ServiceRegistrar registrar = lookup.getRegistrar();
			Class[] classes = new Class[] {TransactionManager.class};
			TransactionManager tmp = (TransactionManager) registrar.lookup(new ServiceTemplate(null, classes, null));
			return tmp;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	@Override
	public void registerWithBank() {
		try {
			HttpSession session = getSession();
	        String firstName = (String)session.getAttribute("firstname");
	        String familyName = (String)session.getAttribute("familyname");
	        String postalCode = (String)session.getAttribute("postalcode");
	        
			BankInterface tmp = getBank();
			UUID id = tmp.register(firstName, familyName, postalCode);
			
			session.setAttribute("bankaccount", id.toString());
		} catch(Exception e) {
			e.printStackTrace();
		}
	
	}
	
	@Override
	public void credit(double amount) {
		try {
			HttpSession session = getSession();
			BankInterface tmp = getBank();
			tmp.credit(UUID.fromString((String)session.getAttribute("bankaccount")), amount);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void offerProduct(String name, long duration, double minAmount, double maxAmount, String auctionType) {
		try {
			StoreConnectorInterface connector = getStoreConnector();
			BankInterface bank = getBank();
			HttpSession session = getSession();
			connector.addProduct(new Product(name), duration, minAmount, maxAmount, Class.forName(auctionType), null, UUID.fromString((String)session.getAttribute("bankaccount")), bank);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public String search(String term, int index) {
		try {
			StoreConnectorInterface connector = getStoreConnector();
			Vector<Product> searchResult = connector.search(term);
			return searchResult.get(index).getID().toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "Not found";
	}
	
	@Override
	public void joinBidding(String productId) {
		try {
			HttpSession session = getSession();

			//Get JavaSpace and Transaction Manager
			JavaSpace space = this.getSpace();
			TransactionManager transManager = this.getTransactionManager();
			
			//Initialize transaction
			Created created = TransactionFactory.create(transManager, 5000);
			Transaction trans = created.transaction;
			
			//Create and write entry
			String name = session.getAttribute("firstname") + " " + session.getAttribute("lastname");
			JoinRequest entry = new JoinRequest(UUID.fromString(productId), null, name);
			space.write(entry, trans, 24*60*60);

			trans.commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void placeBidding(String productId, double amount) {
		try {
			HttpSession session = getSession();

			//Get JavaSpace and Transaction Manager
			JavaSpace space = this.getSpace();
			TransactionManager transManager = this.getTransactionManager();
			
			//Initialize transaction
			Created created = TransactionFactory.create(transManager, 5000);
			Transaction trans = created.transaction;
			
			//Create and write entry
			Double amountNP = new Double(amount);
			String street = (String) session.getAttribute("street");
			String streetNumber = (String) session.getAttribute("number");
			String postalCode = (String) session.getAttribute("postalcode");
			String city = (String) session.getAttribute("city");
			String country = (String) session.getAttribute("country");
			Address address = new Address(street, streetNumber, postalCode, city, country);
			Bidding entry = new Bidding(UUID.fromString(productId), null, UUID.fromString((String)session.getAttribute("bankaccount")), getBank(), amountNP, address);
			space.write(entry, trans, 24*60*60);

			trans.commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public Image downloadImage(String name) {
 		try { 
			String currentDir = new File(".").getAbsolutePath();
			File file = new File(currentDir + "/" + name);
			return ImageIO.read(file);
		} catch (IOException e) {
			System.out.println("image read failed");
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean uploadImage(String name, Image image) {
		try {
			String currentDir = new File("").getAbsolutePath();
			File file = new File(currentDir + "/" + name);
			int mid = name.lastIndexOf(".");
			String format = name.substring(mid+1,name.length());
			System.out.println("format " + format);
			file.createNewFile();
			System.out.println("write file to : " + file.toString());
			ImageIO.write((BufferedImage)image, format, file);
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
}